package com.hawthorn.admin.service.sysuser.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hawthorn.admin.constant.DicConstants;
import com.hawthorn.admin.feign.redisService.RedisUserFeignService;
import com.hawthorn.admin.model.po.AppUserPO;
import com.hawthorn.admin.repository.AppUserMapper;
import com.hawthorn.admin.repository.SysUserMapper;
import com.hawthorn.admin.repository.SysUserRoleMapper;
import com.hawthorn.admin.repository.SysUserTmpMapper;
import com.hawthorn.admin.service.sysuser.SysUserService;
import com.hawthorn.component.constant.DicConstant;
import com.hawthorn.component.constant.FormatConstant;
import com.hawthorn.component.constant.RedisConstant;
import com.hawthorn.component.utils.bean.Map2ObjUtil;
import com.hawthorn.component.utils.security.PasswordEncoder;
import com.hawthorn.component.utils.security.PasswordUtils;
import com.hawthorn.entity.po.SysUserPO;
import com.hawthorn.entity.po.SysUserRolePO;
import com.hawthorn.platform.context.ContextHolder;
import com.hawthorn.platform.exception.BizCode;
import com.hawthorn.platform.redis.RedisMyClient;
import com.hawthorn.platform.service.ExcelApiService;
import com.hawthorn.platform.service.TransResultService;
import com.hawthorn.platform.utils.common.ArrayMyUtil;
import com.hawthorn.platform.utils.common.MyUtil;
import com.hawthorn.platform.utils.common.StrMyUtil;
import com.hawthorn.platform.utils.iassert.AssertMyUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>todo 系统用户service</p>
 * @author: andyten@tom.com | xukaixing@hotmail.com
 * @created: 2021/11/29 5:01 PM
 * @version v1.0.2
 * @copyright: Copyright (c)  andyten
 */
@Service
@Slf4j
public class SysUserServiceImpl implements SysUserService
{
  @Resource
  private SysUserMapper sysUserMapper;
  @Resource
  private SysUserRoleMapper sysUserRoleMapper;
  @Autowired
  private SysUserTmpMapper sysUserTmpMapper;
  @Resource
  private AppUserMapper appUserMapper;
  @Resource
  private TransResultService transResultService;
  @Resource
  private ExcelApiService excelApiService;
  @Resource
  private RedisMyClient redisMyClient;
  @Resource
  private RedisUserFeignService redisUserFeignService;

  private HashMap<String, String> getTransHash()
  {
    HashMap<String, String> transHash = new HashMap<>();
    transHash.put("deptType", "dic|zzlx");
    transHash.put("bizType", "dic|ywlx");
    transHash.put("status", "dic|yxzt");
    transHash.put("userType", "dic|yhlx");
    transHash.put("userLevel", "dic|zzlx");
    transHash.put("postStation", "dic|qdgw");
    transHash.put("exField4", "dic|sf");
    transHash.put("exField5", "dic|sf");
    transHash.put("sex", "dic|xb");
    transHash.put("deptId", "dept|o");
    transHash.put("createBy", "user|o");
    transHash.put("createTime", "date|" + FormatConstant.SIMPLE_DATE_TIME_FORMAT);
    transHash.put("birthDate", "date|" + FormatConstant.SIMPLE_DATE_FORMAT);

    return transHash;
  }

  /**
   * <p>todo 查询用户信息</p>
   * @param: page
   * @param: conditions
   * @return: com.baomidou.mybatisplus.core.metadata.IPage<java.util.Map < java.lang.String, java.lang.Object>>
   * @author: andy.ten@tom.com | xukaixing@hotmail.com
   * @date: 2022/8/2 12:54
   * @version: 1.0.1
   * Modification History:
   * Date         Author          Version            Description
   * -----------------------------------------------------------
   * 2022/8/2    andy.ten        v1.0.1             init
   */
  @Override
  public IPage<Map<String, Object>> findUsers(Page<Map<String, Object>> page, String conditions)
  {
    // 设置排序
    OrderItem oi = new OrderItem();
    oi.setColumn("u.create_time");
    oi.setAsc(false);
    List<OrderItem> al = page.getOrders();
    al.add(oi);
    page.setOrders(al);
    return transResultService.transResult(sysUserMapper.findUsers(page, conditions), getTransHash());
  }

  /**
   * <p>todo 查询用户信息</p>
   * @param: page
   * @param: conditions
   * @return: com.baomidou.mybatisplus.core.metadata.IPage<java.util.Map < java.lang.String, java.lang.Object>>
   * @author: andy.ten@tom.com | xukaixing@hotmail.com
   * @date: 2022/8/2 12:54
   * @version: 1.0.1
   * Modification History:
   * Date         Author          Version            Description
   * -----------------------------------------------------------
   * 2022/8/2    andy.ten        v1.0.1             init
   */
  @Override
  public IPage<Map<String, Object>> findUsersList(Page<Map<String, Object>> page, String conditions)
  {
    // 设置排序
    OrderItem oi = new OrderItem();
    oi.setColumn("u.account");
    oi.setAsc(false);
    List<OrderItem> al = page.getOrders();
    al.add(oi);
    page.setOrders(al);
    return transResultService.transResult(sysUserMapper.findUsersList(page, conditions), getTransHash());
  }

  @Override
  public IPage<Map<String, Object>> findDealerUsers(Page<Map<String, Object>> page, String conditions)
  {
    // 设置排序
    OrderItem oi = new OrderItem();
    oi.setColumn("u.create_time");
    oi.setAsc(false);
    List<OrderItem> al = page.getOrders();
    al.add(oi);
    page.setOrders(al);
    return transResultService.transResult(sysUserMapper.findDealerUsers(page, conditions), getTransHash());
  }

  @Override
  public IPage<Map<String, Object>> findImportUsers(Page<Map<String, Object>> page, String qc)
  {
    HashMap<String, String> transHash = new HashMap<>();
    return transResultService.transResult(sysUserTmpMapper.findImportUsers(page, qc), transHash);
  }

  @Override
  public IPage<Map<String, Object>> findUserLoginInfo(Page<Map<String, Object>> page, String conditions)
  {
    // 设置排序
    OrderItem oi = new OrderItem();
    oi.setColumn("create_time");
    oi.setAsc(false);
    List<OrderItem> al = page.getOrders();
    al.add(oi);
    page.setOrders(al);
    // 绑定字典
    HashMap<String, String> transHash = new HashMap<>();
    transHash.put("loginTime", "date|" + FormatConstant.SIMPLE_DATE_TIME_FORMAT);
    return transResultService.transResult(sysUserMapper.findUserLoginInfo(page, conditions), transHash);
  }

  /**
   * <p>todo 保存新增用户信息</p>
   * @param:
   * @return: com.hawthorn.entity.dto.SysUserDTO
   * @author: andyten@tom.com | xukaixing@hotmail.com
   * @date: 2021/11/10 9:07 PM
   * @version: 1.0.1
   * Modification History:
   * Date         Author          Version            Description
   * -----------------------------------------------------------
   * 2021/11/10    andy.ten        v1.0.1             init
   */
  @Override
  public Map<String, Object> saveUser(Map<String, Object> param)
  {
    SysUserPO sysUserPO = Map2ObjUtil.toObject(param, SysUserPO.class);
    AssertMyUtil.notNull(sysUserPO, BizCode.VARIABLE_NOT_NULL, "sysUserPO");
    // 判断账号是否已存在
    Integer userIsExist = sysUserMapper.findUserByAccount(sysUserPO.getAccount());
    if (userIsExist != 0)
    {
      AssertMyUtil.errMsg(BizCode.USER_ALREADY_REG);
    }
    // 如果联系方式不为空判断联系方式是否相同
    if (!StringUtils.isEmpty(sysUserPO.getMobile()))
    {
      Integer mobileIsExist = sysUserMapper.findUserByMobile(sysUserPO.getMobile());
      if (mobileIsExist != 0)
      {
        AssertMyUtil.errMsg("联系方式已经存在");
      }
    }

    // 设置初始密码
    String salt = PasswordUtils.getSalt();
    PasswordEncoder encoderMd5 = new PasswordEncoder(salt, "MD5");
    String password = encoderMd5.encode("123456"); // 默认密码123456
    sysUserPO.setPassword(password);
    sysUserPO.setSalt(salt);

    // 设置company、oemCompany
    if (sysUserPO.getDeptId() == null)
    {
      sysUserPO.setDeptId(ContextHolder.getDeptId());
    }
    boolean flag = false;
    // 判断所选角色是否包含经销商
    String rid = MyUtil.getValue(param.get("rid"));
    String[] roleIdArr = rid.split(",");
    for (String s : roleIdArr)
    {
      String roleCode = redisMyClient.getRoleCode(s);
      if (!StringUtils.isEmpty(roleCode) && "JXS001".equals(roleCode))
      {
        flag = true;
        break;
      }
    }
    if (flag)
    {
      boolean isExist = existCustomer(sysUserPO.getDeptId(), null);
      if (isExist)
      {
        AssertMyUtil.errMsg("已经存在经销商管理员！");
      }
    }
    Map deptInfo = redisMyClient.getDeptInfo(sysUserPO.getDeptId());
    if (deptInfo == null || deptInfo.isEmpty())
    {
      AssertMyUtil.errMsg("redis中获取dept信息失败");
    }
    sysUserPO.setCompanyId(!StringUtils.isEmpty(deptInfo.get("companyId")) ? Long.valueOf(MyUtil.getValue(deptInfo.get(
        "companyId"))) : null);
    sysUserPO.setOemCompanyId(!StringUtils.isEmpty(deptInfo.get("oemCompanyId")) ?
        Long.valueOf(MyUtil.getValue(deptInfo.get("oemCompanyId"))) : null);
    sysUserPO.setDeptCode(MyUtil.getValue(deptInfo.get("dcode")));
    // sysUserPO.setUserLevel(!StringUtils.isEmpty(deptInfo.get("level")) ?
    //     Integer.valueOf(MyUtil.getValue(deptInfo.get("level"))) : null);

    // 设置菜单布局参数

    // 设置默认主题颜色
    sysUserPO.setThemeType(redisMyClient.getAppLayoutTheme());

    sysUserMapper.save(sysUserPO);
    //同步到APP_USER表
    String oldPhone = sysUserPO.getMobile();
    synchroAppUser(sysUserPO, oldPhone);
    // todo: 同步到redis
    redisUserFeignService.saveUser(sysUserPO);

    // 超级管理员无需处理
    if (!DicConstant.YHLX_03.equals(sysUserPO.getUserType().toString()))
      afterSave(param, sysUserPO);
    return transResultService.transResult(sysUserPO.toMaps(), getTransHash());
  }

  private boolean existCustomer(Long deptId, Long userId)
  {
    boolean flag = false;
    //通过DEPT_ID，查出来这个经销商下所有的用户，然后用户关联角色，判断拥有JXS001角色的用户数量
    Integer count = sysUserMapper.selectCustomerCount(deptId, userId);
    if (count > 0)
    {
      flag = true;
    }
    return flag;
  }

  private void synchroAppUser(SysUserPO sysUserPO, String oldPhone)
  {

    // 验证appuser是否存在
    LambdaQueryWrapper<AppUserPO> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(AppUserPO::getPhone, oldPhone);
    queryWrapper.eq(AppUserPO::getUserKind, 102201);
    queryWrapper.ne(AppUserPO::getBizType, 102402);
    AppUserPO appUser = appUserMapper.selectOne(queryWrapper);
    if (StringUtils.isEmpty(appUser))
    {
      appUser = new AppUserPO();
    }
    appUser.setStatus(sysUserPO.getStatus());
    // 判断是否为PDA用户
    if (DicConstant.SF_01.equals(sysUserPO.getExField4()) && DicConstant.SF_02.equals(sysUserPO.getExField5()))
    {
      appUser.setBizType("102403");
    }
    // 判断是否为麒麟通用户
    else if (DicConstant.SF_01.equals(sysUserPO.getExField5()) && DicConstant.SF_02.equals(sysUserPO.getExField4()))
    {
      appUser.setBizType("102401");
    }
    //判断是否为麒麟通用户和PDA
    else if (DicConstant.SF_01.equals(sysUserPO.getExField4()) && DicConstant.SF_01.equals(sysUserPO.getExField5()))
    {
      appUser.setBizType("102401,102403");
    }
    // 都不是将原有用户设置成无效
    else
    {
      // id不为空证明appuser中存在此用户则将用户状态置为无效
      if (!StringUtils.isEmpty(appUser.getId()))
      {
        appUser.setStatus(Integer.parseInt(DicConstants.YXZT_02));
      } else
      {
        return;
      }
    }
    //更新或插入appuser
    appUser.setPhone(sysUserPO.getMobile());
    appUser.setUserName(sysUserPO.getUserName());
    appUser.setDeptId(sysUserPO.getDeptId());
    appUser.setSysUserId(sysUserPO.getId());
    appUser.setCompanyId(sysUserPO.getCompanyId());
    appUser.setOemCompanyId(sysUserPO.getOemCompanyId());
    appUser.setDeptCode(sysUserPO.getDeptCode());
    appUser.setUserKind(102201L);
    appUser.setSysUserAccount(sysUserPO.getAccount());
    appUserMapper.saveOrUpdate(appUser);

  }

  /**
   * <p>todo 修改用户信息</p>
   * @param: sysUserDTO
   * @return: java.util.Map<java.lang.String, java.lang.Object>
   * @author: andyten@tom.com | xukaixing@hotmail.com
   * @date: 2021/11/11 7:15 PM
   * @version: 1.0.1
   * Modification History:
   * Date         Author          Version            Description
   * -----------------------------------------------------------
   * 2021/11/11    andy.ten        v1.0.1             init
   */
  @Override
  public Map<String, Object> updateUser(Long id, Map<String, Object> param)
  {
    AssertMyUtil.notNull(id, BizCode.METHOD_ARGS_NOTNULL, "id");
    SysUserPO sysUserPO = sysUserMapper.selectById(id);
    //  用户原始手机号
    String oldPhone = sysUserPO.getMobile();
    Map2ObjUtil.toObject(param, sysUserPO);

    // 如果联系方式不为空判断联系方式是否相同
    if (!StringUtils.isEmpty(sysUserPO.getMobile()))
    {
      LambdaQueryWrapper<SysUserPO> queryWrapper = new LambdaQueryWrapper<>();
      queryWrapper.eq(SysUserPO::getMobile, sysUserPO.getMobile());
      queryWrapper.ne(SysUserPO::getId, sysUserPO.getId());
      Integer mobileIsExist = sysUserMapper.selectCount(queryWrapper);
      if (mobileIsExist != 0)
      {
        AssertMyUtil.errMsg("联系方式已经存在");
      }
    }
    // 设置company、oemCompany
    Map deptInfo = redisMyClient.getDeptInfo(sysUserPO.getDeptId());
    if (!StringUtils.isEmpty(deptInfo.get("companyId")))
    {
      sysUserPO.setCompanyId(Long.valueOf(MyUtil.getValue(deptInfo.get("companyId"))));
    }
    if (!StringUtils.isEmpty(deptInfo.get("oemCompanyId")))
    {
      sysUserPO.setOemCompanyId(Long.valueOf(MyUtil.getValue(deptInfo.get("oemCompanyId"))));
    }
    // if (!StringUtils.isEmpty(deptInfo.get("level")))
    // {
    //   sysUserPO.setUserLevel(Integer.valueOf(MyUtil.getValue(deptInfo.get("level"))));
    // }

    sysUserMapper.updateById(sysUserPO);
    // 判断所选角色是否包含经销商
    boolean flag = false;
    String rid = MyUtil.getValue(param.get("rid"));
    String[] roleIdArr = rid.split(",");
    for (String s : roleIdArr)
    {
      String roleCode = redisMyClient.getRoleCode(s);
      if (!StringUtils.isEmpty(roleCode) && "JXS001".equals(roleCode))
      {
        flag = true;
        break;
      }
    }
    if (flag)
    {
      boolean isExist = existCustomer(sysUserPO.getDeptId(), sysUserPO.getId());
      if (isExist)
      {
        AssertMyUtil.errMsg("已经存在经销商管理员！");
      }
    }
    //同步到APP_USER表
    // synchroAppUser(sysUserPO, oldPhone);
    // todo: 同步到redis
    //redisUserFeignService.updateUser(sysUserPO);

    // 超级管理员无需处理
    if (!DicConstant.YHLX_03.equals(sysUserPO.getUserType().toString()))
      afterSave(param, sysUserPO);

    return transResultService.transResult(sysUserPO.toMaps(), getTransHash());
  }

  private void afterSave(Map<String, Object> param, SysUserPO sysUserPO)
  {
    // todo: 分配角色
    sysUserRoleMapper.remove(Wrappers.<SysUserRolePO>query().lambda().eq(SysUserRolePO::getUserId, sysUserPO.getId()));
    String rid = MyUtil.getValue(param.get("rid"));
    if (StrMyUtil.isNotEmpty(rid))
    {
      String[] roleIdArr = rid.split(",");
      List<SysUserRolePO> list = new ArrayList<>();
      for (String s : roleIdArr)
      {
        SysUserRolePO sysUserRolePO = new SysUserRolePO();
        sysUserRolePO.setUserId(sysUserPO.getId());
        sysUserRolePO.setUserAccount(sysUserPO.getAccount());
        sysUserRolePO.setRoleId(Long.valueOf(s));
        sysUserRolePO.setRoleCode(redisMyClient.getRoleCode(s));
        list.add(sysUserRolePO);
      }
      sysUserRoleMapper.saveBatch(list, SysUserRolePO.class);
    }

    // todo: 更新用户角色关系缓存
    String userRoleKey = StrMyUtil.placeHolder(RedisConstant.REDIS_KEY_USERROLE_PREFIX, sysUserPO.getAccount());
    redisMyClient.set(userRoleKey, rid.replaceAll(",", ":"));
    // todo: 删除用户的角色菜单缓存
    String userRoleMenuKey = StrMyUtil.placeHolder(RedisConstant.REDIS_KEY_ROLEMENU_PREFIX, sysUserPO.getAccount());
    redisMyClient.del(userRoleMenuKey);
  }

  /**
   * <p>todo 导出excel</p>
   * @param: response
   * @param: params
   * @return: void
   * @author: andy.ten@tom.com | xukaixing@hotmail.com
   * @date: 2021/12/25 4:18 PM
   * @version: 1.0.1
   * Modification History:
   * Date         Author          Version            Description
   * -----------------------------------------------------------
   * 2021/12/25    andy.ten        v1.0.1             init
   */
  @Override
  public void exportUserData(HttpServletResponse response, String fileName, Map<String, Object> params)
  {
    String header = MyUtil.getValue(params.get("header"));
    String param = MyUtil.getValue(params.get("params"));
    String qc = MyUtil.getConditionsWhere(param, null);
    List<List<String>> headList = new ArrayList<>();
    List<String> headFields = excelApiService.toHeader(header, headList);
    String fields = ArrayMyUtil.join(headFields.toArray(), ",");
    List<Map<String, Object>> dataList = sysUserMapper.exportUsers(fields, qc);
    excelApiService.export(response, fileName, headFields, headList, dataList, getTransHash());
  }


  /**
   * <p>todo 获取用户详细信息</p>
   * @param: userId
   * @return: java.util.Map<java.lang.String, java.lang.Object>
   * @author: andy.ten@tom.com | xukaixing@hotmail.com
   * @date: 2022/8/1 16:18
   * @version: 1.0.1
   * Modification History:
   * Date         Author          Version            Description
   * -----------------------------------------------------------
   * 2022/8/1    andy.ten        v1.0.1             init
   */
  @Override
  public Map<String, Object> getUserInfoById(String userId)
  {
    Map<String, Object> userInfo = sysUserMapper.selectUserInfoById(userId);
    HashMap<String, String> transHash = new HashMap<>();
    //字典转换
    transHash.put("sex", "dic|xb");
    return transResultService.transResult(userInfo, transHash);
  }

  /**
   * <p>todo 更新用户状态</p>
   * @param: id
   * @param: status
   * @return: java.util.Map<java.lang.String, java.lang.Object>
   * @author: andy.ten@tom.com | xukaixing@hotmail.com
   * @date: 2022/8/1 16:18
   * @version: 1.0.1
   * Modification History:
   * Date         Author          Version            Description
   * -----------------------------------------------------------
   * 2022/8/1    andy.ten        v1.0.1             init
   */
  @Override
  public Map<String, Object> updateUserStatus(Long id, Integer status, String rid, Long deptId)
  {
    if (StrMyUtil.isNotEmpty(rid))
    {
      boolean flag = false;
      String[] roleIdArr = rid.split(",");
      for (String s : roleIdArr)
      {
        String roleCode = redisMyClient.getRoleCode(s);
        if (!StringUtils.isEmpty(roleCode) && "JXS001".equals(roleCode))
        {
          flag = true;
          break;
        }
      }
      if (flag)
      {
        // 证明此角色为经销商需要将此经销商下所有的用户，都改成无效/有效
        List<String> userList = sysUserMapper.selectUserList(deptId);
        if (!StringUtils.isEmpty(userList) && !userList.isEmpty())
        {
          for (String userId : userList)
          {
            SysUserPO sysUserPO = sysUserMapper.selectById(userId);
            // 如果状态改变，改变appuser状态
            if (!StringUtils.isEmpty(sysUserPO.getMobile()))
            {
              LambdaQueryWrapper<AppUserPO> queryWrapper = new LambdaQueryWrapper<>();
              queryWrapper.eq(AppUserPO::getPhone, sysUserPO.getMobile());
              queryWrapper.ne(AppUserPO::getBizType, 102402);// 排除麒麟云店用户
              AppUserPO appUser = appUserMapper.selectOne(queryWrapper);
              appUser.setStatus(status);
              appUserMapper.updateById(appUser);
            }
            sysUserMapper.update(sysUserPO, new UpdateWrapper<SysUserPO>().set("status", status).eq("id", userId));
            // todo: 同步到redis
            redisUserFeignService.updateUser(sysUserPO);
          }
          return null;
        }
      }
    }
    SysUserPO sysUserPO = sysUserMapper.selectById(id);
    // 如果状态改变，改变appuser状态
    if (!StringUtils.isEmpty(sysUserPO.getMobile()))
    {
      LambdaQueryWrapper<AppUserPO> queryWrapper = new LambdaQueryWrapper<>();
      queryWrapper.eq(AppUserPO::getPhone, sysUserPO.getMobile());
      AppUserPO appUser = appUserMapper.selectOne(queryWrapper);
      appUser.setStatus(status);
      appUserMapper.updateById(appUser);
    }
    sysUserMapper.update(sysUserPO, new UpdateWrapper<SysUserPO>().set("status", status).eq("id", id));
    // todo: 同步到redis
    redisUserFeignService.updateUser(sysUserPO);
    return sysUserPO.toMaps();
  }

  @Override
  public Map<String, Object> selectUserInfoById(Map<String, Object> params)
  {
    AssertMyUtil.notNull(params, BizCode.METHOD_ARGS_NOTNULL, "params");
    String userId = params.get("userId").toString();
    Map<String, Object> userMap = sysUserMapper.selectUserInfo(userId);
    return userMap;
  }
}
